In [118]:
import pandas as pd
import numpy as np
import yfinance as yf
import random
from matplotlib import pyplot as plt
import seaborn as sns
import warnings
import secrets
import plotly as plotly
import plotly.express as px
from tqdm import tqdm
import plotly.graph_objects as go
pd.set_option('plotting.backend', 'matplotlib')
plotly.offline.init_notebook_mode()
#warnings.simplefilter(action='ignore', category=FutureWarning)
PORTFOLIO ONLY IWDA
In [97]:
TICKER="IWDA.AS"
NUMBER_OF_SIMULATIONS=1000
STARTING_CAPITAL = 10000
YEARS_OF_SIMULATION=30
In [98]:
YEARS_OF_SIMULATION=YEARS_OF_SIMULATION+1
Market_Days=253
df=yf.download(TICKER)["Adj Close"].pct_change(1).dropna()
[*********************100%%**********************] 1 of 1 completed
In [99]:
df.plot()
Out[99]:
<Axes: xlabel='Date'>
In [100]:
df
Out[100]:
Date
2009-09-28 0.000000
2009-09-29 0.000000
2009-09-30 0.000000
2009-10-01 0.000000
2009-10-02 0.000000
...
2023-11-09 0.004418
2023-11-10 -0.002393
2023-11-13 0.007003
2023-11-14 0.006568
2023-11-15 0.003582
Name: Adj Close, Length: 3622, dtype: float64
In [101]:
df_simulations=np.zeros((YEARS_OF_SIMULATION,NUMBER_OF_SIMULATIONS))
df_simulations[0,:]=STARTING_CAPITAL
for x in tqdm(range(0,NUMBER_OF_SIMULATIONS)):
for i in range(1,YEARS_OF_SIMULATION):
annual_change=1
for k in range(Market_Days):
annual_change=annual_change*(1+(secrets.choice(df.iloc[:])))
df_simulations[i,x]=annual_change*df_simulations[i-1,x]
df_simulations= pd.DataFrame(df_simulations)
df_simulations_1= pd.DataFrame(df_simulations)
100%|██████████| 1000/1000 [03:22<00:00, 4.95it/s]
In [102]:
df_simulations_1
Out[102]:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | ... | 1.000000e+04 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 | 10000.000000 |
| 1 | 12313.368079 | 10840.329743 | 12534.749650 | 7687.461219 | 9597.238724 | 10504.787151 | 11593.289800 | 13066.498185 | 10892.408553 | 9092.878159 | ... | 1.289220e+04 | 8274.641896 | 8417.425507 | 14871.171902 | 16996.515440 | 9930.746417 | 10276.650672 | 10154.226516 | 12731.094972 | 11751.471399 |
| 2 | 13303.815309 | 9973.670746 | 19184.333676 | 8453.172699 | 11674.197753 | 14142.583734 | 10903.721436 | 10082.400191 | 12598.207368 | 8369.250287 | ... | 1.402854e+04 | 12786.304914 | 9189.680820 | 17700.856270 | 16732.364996 | 8314.550980 | 11027.800910 | 11306.289640 | 10781.913329 | 11709.048027 |
| 3 | 16414.933792 | 10390.412961 | 17912.959775 | 8979.691504 | 16491.934235 | 15598.501539 | 11263.564228 | 11695.297533 | 11979.422208 | 8622.415527 | ... | 1.462150e+04 | 16509.016624 | 11615.766194 | 20473.440202 | 23059.060898 | 10076.905410 | 11237.874621 | 14251.208558 | 10827.234434 | 12561.406480 |
| 4 | 17780.665601 | 14310.046252 | 24571.133799 | 9983.826905 | 16086.436354 | 14803.074173 | 12507.071491 | 13694.356004 | 10782.445705 | 10054.500035 | ... | 1.615398e+04 | 12931.477983 | 16441.395710 | 19721.108779 | 23107.795807 | 12470.736007 | 12458.421972 | 16211.331076 | 10232.734681 | 15779.190060 |
| 5 | 19662.591981 | 17444.678303 | 30092.546212 | 13730.743680 | 20515.879817 | 12771.902110 | 13084.471496 | 14577.679356 | 11938.104495 | 9319.563972 | ... | 1.769999e+04 | 13379.504387 | 24783.277005 | 17180.261234 | 31159.245051 | 14272.928375 | 14241.566165 | 20165.330111 | 11537.095960 | 17710.357345 |
| 6 | 24724.293231 | 17908.797461 | 28109.207649 | 17586.382679 | 20756.437085 | 14994.499497 | 12826.700016 | 16229.888510 | 13186.232550 | 7583.554704 | ... | 1.704240e+04 | 16436.862368 | 25128.482984 | 20497.506966 | 41526.855050 | 14532.203469 | 16419.685271 | 23012.029959 | 12734.301750 | 15811.116475 |
| 7 | 26870.685969 | 19181.851998 | 27138.246144 | 18055.699638 | 21016.434914 | 15457.620936 | 12496.136742 | 19342.220823 | 15374.527672 | 10198.466927 | ... | 2.213815e+04 | 18580.759614 | 23392.800767 | 23496.664367 | 48830.313101 | 19822.901292 | 15764.151719 | 29068.061535 | 12379.445756 | 19618.532713 |
| 8 | 28364.929989 | 19690.376303 | 27133.262451 | 14380.166818 | 23056.063207 | 16661.940125 | 14216.047540 | 16806.205708 | 23697.830062 | 10208.561808 | ... | 3.129905e+04 | 20624.090058 | 33047.079222 | 26216.930707 | 54948.511260 | 24056.504079 | 17085.186959 | 32982.928774 | 12609.287810 | 22335.700548 |
| 9 | 21435.751203 | 16659.597981 | 32916.813876 | 16688.883268 | 21485.893992 | 16006.937047 | 14455.631334 | 16813.512634 | 30175.329717 | 11853.012990 | ... | 3.696291e+04 | 18802.404569 | 37703.535015 | 37438.871154 | 49275.898620 | 26768.662262 | 22911.900618 | 41017.897443 | 15625.323866 | 20771.394192 |
| 10 | 34411.930605 | 16450.835483 | 30857.292342 | 14447.151756 | 21217.345715 | 17263.889039 | 14143.594347 | 19241.401966 | 32836.033114 | 10491.262187 | ... | 3.896243e+04 | 22886.052293 | 41208.553923 | 38412.908630 | 45504.610773 | 34727.437382 | 25670.124114 | 44651.775568 | 18201.521963 | 24385.687233 |
| 11 | 37313.637894 | 21527.637729 | 35408.454845 | 15464.789264 | 21715.206197 | 19416.984384 | 14537.248687 | 21126.984870 | 40936.545960 | 9524.201521 | ... | 3.512628e+04 | 22075.853908 | 50681.666565 | 37752.203184 | 57493.000542 | 38549.358061 | 28039.234019 | 44892.490229 | 17393.278431 | 22273.664565 |
| 12 | 42219.465799 | 25908.992702 | 36422.526854 | 17880.059039 | 28797.927656 | 21601.946891 | 17042.298566 | 21865.466641 | 44774.183203 | 11393.314445 | ... | 4.455291e+04 | 26300.790348 | 64247.582424 | 46716.700976 | 71211.540819 | 58003.673568 | 39808.703149 | 42597.367462 | 19169.354906 | 26711.926616 |
| 13 | 40858.421164 | 28704.555726 | 42682.721745 | 20705.902232 | 34945.887249 | 19429.798128 | 19341.362992 | 18728.234119 | 51487.851186 | 10598.535387 | ... | 5.386171e+04 | 20339.207601 | 53006.029123 | 51703.407535 | 72586.762203 | 72804.971313 | 40764.571118 | 56625.203349 | 18658.082373 | 34483.019150 |
| 14 | 50576.480520 | 31914.794552 | 37610.259066 | 21203.736565 | 31152.538629 | 18547.781703 | 26096.766561 | 16469.909818 | 58385.088184 | 10213.265114 | ... | 7.581662e+04 | 22142.817684 | 57498.582225 | 61409.822498 | 76578.545128 | 76958.259941 | 46152.925105 | 70877.368581 | 20716.208069 | 59040.599507 |
| 15 | 56203.350367 | 43029.089262 | 42801.965884 | 20683.166026 | 30644.781218 | 15591.238827 | 28187.001203 | 18068.497556 | 75980.453048 | 9294.673834 | ... | 1.042675e+05 | 22412.130199 | 69491.259376 | 77931.388960 | 94800.367175 | 73916.061234 | 57833.151844 | 68232.394318 | 22449.562581 | 66263.743268 |
| 16 | 65531.569348 | 52508.536325 | 45257.399508 | 23589.335981 | 38519.809718 | 16945.671066 | 30403.258969 | 17607.134542 | 96747.092610 | 9919.680061 | ... | 1.197204e+05 | 25672.673422 | 103981.683561 | 74766.453352 | 113748.191541 | 76967.430808 | 69490.935923 | 57258.591070 | 21141.673865 | 83681.353593 |
| 17 | 75049.399598 | 56588.459175 | 59151.890101 | 34529.586253 | 38542.264059 | 20220.536155 | 38972.746751 | 24141.431159 | 114336.590366 | 11862.871690 | ... | 1.236718e+05 | 29938.830894 | 109935.694435 | 57112.932014 | 112566.882129 | 99855.042464 | 74887.821055 | 62559.185461 | 20448.622061 | 75342.646491 |
| 18 | 81978.734598 | 56705.308780 | 90867.736407 | 40983.236107 | 43359.406779 | 16217.552392 | 45131.294845 | 33645.889985 | 105963.440540 | 16996.334739 | ... | 1.642433e+05 | 27695.956254 | 136110.897887 | 88494.065995 | 135855.938620 | 115044.901980 | 69742.897636 | 55518.476505 | 23309.735032 | 138700.064428 |
| 19 | 82255.767710 | 66608.156543 | 124491.047097 | 47975.459602 | 56663.938339 | 21488.865096 | 62685.410862 | 25291.202925 | 143584.589374 | 23181.097481 | ... | 2.140890e+05 | 30899.022740 | 142556.973950 | 96742.401484 | 132638.009605 | 145818.668159 | 85225.084386 | 61029.042422 | 23007.973352 | 133364.855960 |
| 20 | 92519.845454 | 67097.730683 | 132857.326297 | 49545.404534 | 56009.903132 | 20156.819741 | 67734.933928 | 30851.729547 | 135498.695531 | 25185.864241 | ... | 2.927718e+05 | 32003.971454 | 149092.447996 | 121492.838085 | 170416.146224 | 167123.490917 | 82999.512523 | 61769.441488 | 29207.377857 | 131914.316863 |
| 21 | 93126.898828 | 73488.792731 | 195379.448617 | 42686.611621 | 58210.451453 | 24485.263774 | 87226.308111 | 33504.672679 | 141869.511028 | 29932.059963 | ... | 3.152220e+05 | 34611.075387 | 176099.609374 | 134068.211586 | 175911.328516 | 110157.644733 | 85824.447658 | 72203.588757 | 31933.824676 | 150771.851528 |
| 22 | 98907.810613 | 77318.368912 | 223121.879654 | 44096.557571 | 72864.947233 | 34267.919014 | 120865.308457 | 31310.746524 | 196512.049043 | 40261.136491 | ... | 3.939012e+05 | 46073.709567 | 190730.045606 | 107375.997010 | 217101.173174 | 143523.069373 | 97838.342271 | 89518.838485 | 32778.273963 | 152562.830035 |
| 23 | 166054.723679 | 68917.463398 | 234515.441820 | 41941.582464 | 90243.735799 | 40236.939963 | 105927.257583 | 42561.001581 | 219434.265544 | 62753.252379 | ... | 4.291681e+05 | 49269.780402 | 208612.368599 | 124083.828757 | 340431.102849 | 122364.921536 | 101729.228230 | 104827.992872 | 38673.202973 | 138057.683691 |
| 24 | 144805.011210 | 74483.652259 | 232135.489495 | 49532.377791 | 124089.864518 | 56322.966374 | 119116.195987 | 48374.828764 | 247028.119556 | 72810.576403 | ... | 5.280528e+05 | 43007.446413 | 220108.777063 | 148980.867555 | 464935.376559 | 149845.664658 | 122912.086124 | 99073.373247 | 48693.817105 | 163157.808913 |
| 25 | 145392.040670 | 67086.595306 | 233757.035881 | 72490.110921 | 124225.553373 | 49297.395422 | 168394.348460 | 52859.716886 | 327855.849657 | 97578.315184 | ... | 6.115322e+05 | 50169.940769 | 294816.461932 | 175022.371948 | 492621.920895 | 141043.344428 | 137474.765379 | 139160.077891 | 46683.736938 | 175515.479592 |
| 26 | 162648.091757 | 82285.190738 | 297468.924164 | 83074.767381 | 141498.043553 | 55192.441419 | 171771.193422 | 47470.441524 | 447606.316005 | 119206.636148 | ... | 7.880187e+05 | 48142.369457 | 312902.011847 | 180889.133799 | 499579.607118 | 176206.983013 | 172790.249051 | 162256.079474 | 43633.208895 | 206603.726424 |
| 27 | 192162.418056 | 89874.832247 | 410338.124143 | 96328.778071 | 125238.563268 | 58704.866866 | 193800.927425 | 45849.314560 | 455922.898430 | 169100.843006 | ... | 1.356221e+06 | 50005.618154 | 324727.437642 | 229473.043969 | 537756.886293 | 228506.772257 | 203117.710784 | 167031.201320 | 51457.384665 | 268911.611947 |
| 28 | 217320.414180 | 117625.464232 | 418249.220724 | 134878.370759 | 106296.719793 | 76693.923606 | 166291.276848 | 53841.226188 | 539213.562380 | 185588.964710 | ... | 1.602376e+06 | 62970.168268 | 436585.872715 | 256943.889911 | 564933.227020 | 237210.389591 | 268932.742116 | 156718.530453 | 60747.727654 | 286710.898382 |
| 29 | 233174.039080 | 124143.641503 | 401251.381888 | 125575.836243 | 130271.735099 | 108155.197672 | 260891.134472 | 74353.757893 | 738108.751432 | 186077.187657 | ... | 1.460656e+06 | 62411.318361 | 413874.778940 | 301208.752440 | 665886.087030 | 265368.157304 | 275959.410861 | 211209.668636 | 83762.352291 | 255689.601318 |
| 30 | 240377.999289 | 148272.715232 | 387555.297204 | 149026.207456 | 196248.731824 | 111558.226816 | 369463.166833 | 70370.818321 | 651561.547213 | 187923.809722 | ... | 1.751063e+06 | 77893.329144 | 394671.158549 | 330067.415847 | 862084.427369 | 333929.278063 | 339723.780659 | 231930.979538 | 81028.843693 | 217273.760962 |
31 rows × 1000 columns
In [103]:
df_simulations=df_simulations_1
df_simulations.iloc[YEARS_OF_SIMULATION-1]
Out[103]:
0 240377.999289
1 148272.715232
2 387555.297204
3 149026.207456
4 196248.731824
...
995 333929.278063
996 339723.780659
997 231930.979538
998 81028.843693
999 217273.760962
Name: 30, Length: 1000, dtype: float64
In [104]:
quantile=df_simulations.iloc[YEARS_OF_SIMULATION-1].quantile([0.1,0.9])
quantile=list(quantile)
print(quantile)
df_simulations_purged=df_simulations[df_simulations.columns[ df_simulations.max() < quantile[1]]]
df_simulations_purged=df_simulations_purged[df_simulations_purged.columns[ df_simulations_purged.max() > quantile[0]]]
[77107.80451093665, 722493.1954776454]
In [105]:
df_simulations_purged.plot(figsize=(16,8), title=f"Simulation of {NUMBER_OF_SIMULATIONS} portfolios", legend=False)
Out[105]:
<Axes: title={'center': 'Simulation of 1000 portfolios'}>
In [106]:
df_simulations_purged.iloc[YEARS_OF_SIMULATION-1].plot.density(figsize=(16,8),fontsize=14, xlim=(-100000,900000))
Out[106]:
<Axes: ylabel='Density'>
In [107]:
top_25 =[]
low_25 =[]
median=[]
for i in range(0,YEARS_OF_SIMULATION):
top_25.append(df_simulations.iloc[i].quantile(0.75))
low_25.append(df_simulations.iloc[i].quantile(0.25))
median.append(df_simulations.iloc[i].median())
columns=["top 25%","median","bottom 25%"]
df_statistics=pd.DataFrame(list(zip(top_25,median,low_25)),columns=columns)
df_statistics
Out[107]:
| top 25% | median | bottom 25% | |
|---|---|---|---|
| 0 | 10000.000000 | 10000.000000 | 10000.000000 |
| 1 | 12348.333554 | 11109.041030 | 10006.396264 |
| 2 | 14200.429839 | 12171.658750 | 10644.066110 |
| 3 | 16418.635680 | 13676.767940 | 11431.689400 |
| 4 | 18909.276997 | 15447.853332 | 12445.011851 |
| 5 | 21832.280496 | 17103.455678 | 13383.796337 |
| 6 | 24311.712250 | 19291.270609 | 15083.357567 |
| 7 | 27630.160441 | 21455.566453 | 16404.243026 |
| 8 | 31317.266818 | 23742.298014 | 17702.520834 |
| 9 | 35751.516445 | 26709.509849 | 19684.756245 |
| 10 | 40584.526039 | 29610.078725 | 21076.053059 |
| 11 | 46602.194852 | 32579.591949 | 23238.045354 |
| 12 | 52432.647163 | 36351.367744 | 24959.929030 |
| 13 | 58051.044836 | 40300.344959 | 27653.064242 |
| 14 | 64439.277873 | 44676.567088 | 29033.616924 |
| 15 | 73011.253750 | 49596.605492 | 32436.192026 |
| 16 | 81804.045282 | 54934.059045 | 35382.782965 |
| 17 | 91913.439542 | 60081.754947 | 38706.836915 |
| 18 | 104947.531211 | 68010.698888 | 41766.153084 |
| 19 | 119253.678346 | 76220.717255 | 44500.758223 |
| 20 | 133079.264218 | 85132.677985 | 51414.917013 |
| 21 | 149362.353497 | 93444.763122 | 54921.073782 |
| 22 | 172351.892497 | 105134.006520 | 59123.171448 |
| 23 | 190731.978616 | 116989.207605 | 67873.036707 |
| 24 | 214912.293196 | 128330.086687 | 73917.881840 |
| 25 | 241144.827277 | 143528.700869 | 83644.505990 |
| 26 | 272189.611973 | 160624.673892 | 89960.393452 |
| 27 | 300701.248346 | 177930.928963 | 100589.507553 |
| 28 | 340332.156706 | 192349.197636 | 107897.510349 |
| 29 | 387153.937670 | 217552.771247 | 122377.502987 |
| 30 | 429483.031623 | 240061.472868 | 134759.454432 |
In [119]:
#ax= df_statistics.plot(legend=None,logy=False,fontsize=20,figsize=(25,15),linewidth=4,color="black",title=f"Simulation of {NUMBER_OF_SIMULATIONS} portfolios")
pd.set_option('plotting.backend', 'plotly')
fig = df_statistics.plot(width=1600, height=800,title=f"Simulation of {NUMBER_OF_SIMULATIONS} portfolios",labels= {"index": "Years to Maturity", "value":"Total Capital"} )
fig.add_trace(go.Scatter(x=list(range(0,YEARS_OF_SIMULATION)),y=np.array(top_25),fill='tonexty',mode='lines', line_color='blue' , fillcolor ="red", showlegend=False, hoverinfo="skip"))
fig.add_trace(go.Scatter(x=list(range(0,YEARS_OF_SIMULATION)),y=np.array(median),fill='tonexty',mode='lines', line_color='orange', fillcolor="green", showlegend=False, hoverinfo="skip"))
In [121]:
ls_simulations_at_profit=[]
for i in range(YEARS_OF_SIMULATION):
c=len([1 for i in list(df_simulations.iloc[i])if i > STARTING_CAPITAL])
ls_simulations_at_profit.append(c/NUMBER_OF_SIMULATIONS*100)
pd.set_option('plotting.backend', 'plotly')
df_simulations_at_profit = pd.DataFrame(ls_simulations_at_profit,columns=["Profit %"])
df_simulations_at_profit.plot(title="Minimum investment horizon", labels= {"index": "Period length in years", "value":"Chance to be in profit"})
In [ ]:
In [ ]:
In [ ]:
TICKER="^GSPC"
In [ ]:
df=yf.download(TICKER)["Adj Close"].pct_change(1).dropna()
df_simulations = np.zeros((YEARS_OF_SIMULATION, NUMBER_OF_SIMULATIONS))
df_simulations[0, :] = STARTING_CAPITAL
for x in tqdm(range(0, NUMBER_OF_SIMULATIONS)):
for i in range(1, YEARS_OF_SIMULATION):
annual_change = 1
for k in range(Market_Days):
annual_change = annual_change * (1 + (secrets.choice(df.iloc[:])))
df_simulations[i, x] = annual_change * df_simulations[i - 1, x]
df_simulations = pd.DataFrame(df_simulations)
df_simulations_1 = pd.DataFrame(df_simulations)
df_simulations = df_simulations_1
df_simulations.iloc[YEARS_OF_SIMULATION - 1]
quantile = df_simulations.iloc[YEARS_OF_SIMULATION - 1].quantile([0.1, 0.9])
quantile = list(quantile)
df_simulations_purged = df_simulations[df_simulations.columns[df_simulations.max() < quantile[1]]]
df_simulations_purged = df_simulations_purged[df_simulations_purged.columns[df_simulations_purged.max() > quantile[0]]]
top_25 =[]
low_25 =[]
median=[]
for i in range(0,YEARS_OF_SIMULATION):
top_25.append(df_simulations.iloc[i].quantile(0.75))
low_25.append(df_simulations.iloc[i].quantile(0.25))
median.append(df_simulations.iloc[i].median())
columns=["top 25%","median","bottom 25%"]
df_statistics=pd.DataFrame(list(zip(top_25,median,low_25)),columns=columns)
pd.set_option('plotting.backend', 'plotly')
fig = df_statistics.plot(width=1600, height=800,title=f"Simulation of {NUMBER_OF_SIMULATIONS} portfolios",labels= {"index": "Years to Maturity", "value":"Total Capital"} )
fig.add_trace(go.Scatter(x=list(range(0,YEARS_OF_SIMULATION)),y=np.array(top_25),fill='tonexty',mode='lines', line_color='blue' , fillcolor ="red", showlegend=False, hoverinfo="skip"))
fig.add_trace(go.Scatter(x=list(range(0,YEARS_OF_SIMULATION)),y=np.array(median),fill='tonexty',mode='lines', line_color='orange', fillcolor="green", showlegend=False, hoverinfo="skip"))
In [ ]:
ls_simulations_at_profit = []
for i in range(YEARS_OF_SIMULATION):
c = len([1 for i in list(df_simulations.iloc[i]) if i > STARTING_CAPITAL])
ls_simulations_at_profit.append(c / NUMBER_OF_SIMULATIONS * 100)
pd.set_option('plotting.backend', 'plotly')
df_simulations_at_profit = pd.DataFrame(ls_simulations_at_profit, columns=["Profit %"])
df_simulations_at_profit.plot(title="Minimum investment horizon",
labels={"index": "Period length in years", "value": "Chance to be in profit"})
In [115]:
In [ ]:
!jupyter nbconvert --execute --to html Portfolio1.ipynb --HTMLExporter.theme=dark
In [ ]: